/*
 *		Now!W3C Compatibility layer - Core
 *		Copyright (C) 2010 The OVMS Free Software Project. All Rights Reserved.
 */

(function ( self, undefined ) {
	/* ==== Malloc ==== */
	var $ = jQuery;	// Ensure $ refers to jQuery
	var arr_hshEventHandlers = [];
	var list_data_ruleFixed = [];
	var listRecalc = [];
	var classPrefix = "NowW3C_Sel_";
	var classPrefix_Root = classPrefix + "Root", classPrefix_Body = classPrefix + "Body";
	var elTemp;
	var isIE = !!(self.ActiveXObject && !self.opera && document.createStyleSheet && self.createPopup);
	var version = parseFloat(navigator.appVersion.split("MSIE")[ 1 ]);
	/* ==== /Malloc ==== */
	
	NowW3C = {
		resultExternal: null	// For external results (eg. from VBScript in IE)
		, dataExternal: { Class: {} }
		, Update: function () {
			var idx, list, len;
			var idx2, list2, len2, data, list_match;
			
			for ( idx = 0, list = list_data_ruleFixed, len = list.length ; idx < len ; ++idx ) {//alert(list[ idx ].selector);
				// Unsupported/invalid selectors will throw an error in jQuery/Sizzle,
				//	silently ignore these for now
				//try {
					$(list[ idx ].selector).addClass(classPrefix + idx);
				//} catch ( e ) {}
			}
			
			var el, rule, val;
			for ( idx = 0, list = document.getElementsByTagName("div"), len = list.length ; idx < len ; ++idx ) {
				el = list[ idx ];
				
				for ( idx2 = 0, list2 = listRecalc, len2 = list2.length ; idx2 < len2 ; ++idx2 ) {
					data = list2[ idx2 ];
					val = el.currentStyle[ data.name ];
					if ( val && (list_match = val.match(data.regex_val)) ) {
						data.fnReplace(list_match, el, val);
					}
				}
			}
		}, ToJSStyle: function ( name ) {
			if ( name === "float" ) { name = "styleFloat"; } // Fix clash with JS keyword
			// For IE6
			if ( name != "min-width" && name != "max-width" && name != "max-height" ) {	
				name = name.replace(/-\w/g, function ( all ) { return all.charAt(1).toUpperCase(); });
			}
			return name;
		}, ToPixels: function( val, elParent ) {
			elParent.appendChild(elTemp);
			elTemp.style.width = val || 0;
			return val === undefined ? undefined : elTemp.offsetWidth;
		}, CalcWidth: function ( el ) {
			var widthMin = NowW3C.ToPixels(el.currentStyle[ NowW3C.ToJSStyle('min-width') ], el.parentNode);
			var widthMax = NowW3C.ToPixels(el.currentStyle[ NowW3C.ToJSStyle('max-width') ], el.parentNode);
			var width = el.parentNode.clientWidth;
			
			if ( widthMin === undefined && widthMax === undefined ) {
				return "auto";
			} else if ( width >= widthMin && width <= widthMax ) {
				return "auto";
			} else {
				return Math.min(widthMax || Infinity, Math.max(widthMin, width)) + "px";
			}
		}, CalcHeight: function ( el ) {
		
		}
	};
	
	// W3C DOM compatibility
	if ( isIE && version < 8 ) {
		// Exception DOMException
		window.DOMException = function DOMException( code ) {
			this.code = code;
		};
		DOMException.prototype = {
			constructor: Object	// Inheritance
			, INDEX_SIZE_ERR: 1			// Index or size is negative, or greater than the allowed value
			, DOMSTRING_SIZE_ERR: 2		// The specified range of text does not fit into a DOMString
			, HIERARCHY_REQUEST_ERR: 3	// Any node is inserted somewhere it doesn't belong
			, WRONG_DOCUMENT_ERR: 4		// A node is used in a different document than the one that created it (that doesn't support it)
			, INVALID_CHARACTER_ERR: 5	// An invalid character is specified, such as in a name
			, NO_DATA_ALLOWED_ERR: 6	// Data is specified for a node which does not support data
			, NO_MODIFICATION_ALLOWED_ERR: 7	// An attempt is made to modify an object where modifications are not allowed
			, NOT_FOUND_ERR: 8			// An attempt was made to reference a node in a context where it does not exist
			, NOT_SUPPORTED_ERR: 9		// The implementation does not support the type of object requested
			, INUSE_ATTRIBUTE_ERR: 10	// An attempt is made to add an attribute that is already inuse elsewhere
		};
		
		// Interface DOMImplementation
		window.DOMImplementation  = function DOMImplementation() {
		};
		DOMImplementation.prototype = {
			constructor: Object	// Inheritance
			, hasFeature: function ( feature, version ) {
				throw new DOMException( "DOMImplementation.hasFeature is not implemented yet." );
			}
		};
		
		// Interface Node
		window.Node = function Node() {
			
		};
		
		// Interface DocumentFragment
		window.DocumentFragment = function DocumentFragment() {	// Expose global & give name
		};
		DocumentFragment.prototype = {
			constructor: Node	// Inheritance
		};
		
		// Interface Document
		window.Document = function Document( doctype, implementation ) {	// Expose global & give name
			/*readonly attribute DocumentType */this.doctype = doctype;
			/*readonly attribute DOMImplementation */this.implementation = implementation;
			/*readonly attribute Element */this.documentElement = null;
		};
		/*Document.prototype = new Node();
		Document.prototype.constructor = Document;
		$.extend(Document.prototype, );
		var d = new Document();
		//Object.prototype.test = 17;
		alert(d.constructor.prototype.createElement);*/
		
		if ( !Array.indexOf ) {
			Array.indexOf = function ( list, item ) {
				var idx = 0, len = list.length;
				for (; idx < len ; ++idx ) {
					if ( list[ idx ] === item ) { return idx; }
				}
				return -1;
			};
		}
		
		function TypeDef( visibility, isReadOnly, type, datatype ) {
			this.visibility = visibility;
			this.isReadOnly = isReadOnly;
			this.type = type;
			this.datatype = datatype;
		}
		TypeDef.PRIVATE = 1;
		TypeDef.PROTECTED = 2;
		TypeDef.PUBLIC = 3;
		TypeDef.ATTRIBUTE = 1;	// Usually a primitive or object, may also be a function
		TypeDef.METHOD = 2;		// Must be a function
		TypeDef.ANY = null;
		
		function Interface( definition, options ) {
			var name, typedef;
			var datatype, type, isReadOnly, visibility;
			for ( name in definition ) {
				typedef = definition[ name ];
				// Get visibility of member (defaults to public)
				visibility = typedef.visibility !== undefined ? typedef.visibility : TypeDef.PUBLIC;
				// Is member read-only?
				isReadOnly = typedef.isReadOnly !== undefined ? typedef.isReadOnly : false;
				// Get type (attribute or method) for the member
				type = typedef.type !== undefined ? typedef.type : TypeDef.ATTRIBUTE;
				// Get datatype for the member
				datatype = (typedef.datatype !== undefined && (typedef.datatype instanceof Function))
					? typedef.datatype : TypeDef.ANY;
			}
		}
		Interface.prototype = {
			// ...
		};
		
		var IDocument = new Interface({
			doctype: { visibility: TypeDef.PUBLIC, isReadOnly: true, type: TypeDef.ATTRIBUTE, datatype: DocumentType }
			, implementation: { visibility: TypeDef.PUBLIC, isReadOnly: true, type: TypeDef.ATTRIBUTE, datatype: DOMImplementation }
			, documentElement: { visibility: TypeDef.PUBLIC, isReadOnly: true, type: TypeDef.ATTRIBUTE, datatype: Element }
		}, {
			extend: null
		});
		
		var IDocument = new Interface({
			doctype: { access: TypeDef.PUBLIC | TypeDef.READONLY | TypeDef.ATTRIBUTE, type: DocumentType }
			, implementation: { access: TypeDef.PUBLIC | TypeDef.READONLY | TypeDef.ATTRIBUTE, type: DOMImplementation }
			, documentElement: { access: PUBLIC|READONLY|ATTRIBUTE, type: Element }
		}, {
			extend: null
		});
		
		var protInheriting = false;
		// "Class" object constructor (yes I know...)
		//	( will return a function which may be used as constructor )
		function Class( fnClassScope, options ) {
			var fnConstruct, cls_priv, cls_prot, cls_pub, regexGen = /^function\s*\(\s*[_g]\s*\)/;
			var isFinal = false;
			var clsExtend, infImplements;
			if ( !options ) { options = {}; }
			
			// [Optional] which class to extend / inherit from
			clsExtend = options.extend;
			// [Optional] which interface to implement / verify against
			infImplements = options.implement;
			
			// Public scope constructor
			cls_pub = function ( /* arg1 ... argN */ ) {
				// Private scope is a private local variable,
				//	public scope is of course the instance
				var priv, prot, pub = this, list_arg;
				var idx, hsh, member;
				
				// Only call constructor & privatise members if not using for inheritance
				if ( !protInheriting ) {
					// Create private scope object
					hsh = priv = new cls_priv();
					
					/* ==== All generator methods must be used ==== */
					// Private methods must receive public scope var "g"
					for ( idx in hsh ) {
						if ( (member = hsh[ idx ]) && (member instanceof Function) && regexGen.test(member.toString()) ) {
							hsh[ idx ] = member(pub);
						}
					}
					// Public methods must receive private scope var "_"
					hsh = this;
					for ( idx in hsh ) {
						if ( (member = hsh[ idx ]) && (member instanceof Function) && regexGen.test(member.toString()) ) {
							hsh[ idx ] = member(priv);
						}
					}
					/* ==== /All generator methods must be used (give private scope var "_") ==== */
					
					list_arg = arguments;
					// Constructors are an exception: always pass "_" as 1st arg
					Array.prototype.unshift.call(list_arg, priv);
					// Use private scope as "this" context within constructor
					fnConstruct.apply(pub, list_arg);
				// A class is inheriting from this one
				} else {
					// Share this class's protected scope constructor
					protInheriting = cls_prot;
				}
			};
			// Protected scope constructor
			cls_prot = function () {};
			// Class should extend from another
			if ( clsExtend ) {
				// Check parent class is valid
				if ( !clsExtend || !(clsExtend instanceof Function) ) { throw new Error( "Class :: Invalid Class provided for extending" ); }
				// Check class is not defined "Final"
				if ( clsExtend.IsFinal() ) { throw new Error( "Class :: Class is declared Final; it cannot be extended" ); }
				protInheriting = true;
				cls_pub.prototype = new clsExtend();
				cls_prot.prototype = new protInheriting();
				protInheriting = false;
			// Root class in a chain
			} else {
				// Protected scope inherits from public scope
				//	( private, relevant protected & public members all available under "_" )
				protInheriting = true;
				cls_prot.prototype = new cls_pub();
				protInheriting = false;
			}
			// Private scope constructor
			//	( extends protected scope constructor )
			cls_priv = function () {};
			cls_priv.prototype = new cls_prot();
			
			// Internal constructors must be kept secret,
			//	and would make little sense anyway if available under "_"
			cls_priv.prototype.constructor = undefined;
			
			$.extend(cls_pub, {
				// Ensure no new classes may extend this one
				Finalise: function () {
					isFinal = true;
				}, IsFinal: function () {
					return isFinal;
				}
			});
			
			// Class has a closure to wrap its own private scope
			//	so run & allow it to set up, providing its internal constructor
			fnConstruct = fnClassScope.call({
				Static: function ( hsh ) {
					$.extend(cls_pub, hsh);
					return this; // Chain
				}, Private: function ( hsh ) {
					$.extend(cls_priv.prototype, hsh);
					return this; // Chain
				}, Protected: function ( hsh ) {
					$.extend(cls_prot.prototype, hsh);
					return this; // Chain
				}, Public: function ( hsh ) {
					// TODO: ensure all methods are func generators ?
					$.extend(cls_pub.prototype, hsh);
					return this; // Chain
				}, Export: function ( name, scope ) {
					// Export to global scope if not specified
					if ( !scope ) { scope = self; }
					scope[ name ] = cls_pub;
					return this; // Chain
				}
			});
			
			// Validate class definition
			if ( !fnConstruct || !(fnConstruct instanceof Function) ) {
				throw new Error( "Class constructor :: Classes must define a Constructor function" );
			}
			
			// Override
			return cls_pub;
		}
		
		var Document = new Class( function () {
			/* ==== Static (Private) ==== */
			var num = 0;
			var isGood = "maybe";
			/* ==== /Static (Private) ==== */
			
			// Static (Public)
			this.Static({
				Count: function () {
					return num;
				}
			// Private members
			}).Private({
				AreWeGoodOrBad: function (g) { return function () {
					return isGood;
				}}
			// Protected members
			}).Protected({
				protVal: "unmodded"
				, WeAreFamily: function (g) { return function () {
					return true;
				}}
			// Public members
			}).Public({
				/*Element */createElement: function (_) { return function ( /*DOMString */tagName ) {
					alert("In createElement: createDocumentFragment = " + _.createDocumentFragment);
					return new Element( tagName );
				}}, /*DocumentFragment */createDocumentFragment: function (_) { return function () {
					return new DocumentFragment();
				}}, /*Text */createTextNode: function (_) { return function ( /*DOMString */data ) {
					return new Text( data );
				}}, /*Comment */createComment: function (_) { return function ( /*DOMString */data ) {
					return new Comment( data );
				}}, /*CDATASection */createCDATASection: function (_) { return function ( /*DOMString */data ) {
					return new CDATASection( data );
				}}, /*ProcessingInstruction */createProcessingInstruction: function (_) { return function ( /*DOMString */target, /*DOMString */data ) {
					return new ProcessingInstruction( target, data );
				}}, /*Attr */createAttribute: function (_) { return function ( /*DOMString */name ) {
					return new Attr( name );
				}}, /*EntityReference */createEntityReference: function (_) { return function ( /*DOMString */name ) {
					return new EntityReference( name );
				}}, /*NodeList */getElementsByTagName: GetElementsByTagName
				, test: function (_) { return function () {
					if ( _.val === undefined ) {
						_.val = 0;
					} else {
						_.val++;
					}
					return _.val < 2 ? _.val : _.val + " " + _.AreWeGoodOrBad();
				}}, AreWeFamily: function (_) { return function () {
					return _.WeAreFamily();
				}}, GetSecrets: function (_) { return function () {
					return _.DontTellMum ? _.DontTellMum() : _.DontTellMum;
				}}
			// Misc.
			}).Export("Document");
			
			// __construct
			return function ( _, doctype, implementation ) {
				/* ==== Public ==== */
				/*readonly attribute DocumentType */this.doctype = doctype;
				/*readonly attribute DOMImplementation */this.implementation = implementation;
				/*readonly attribute Element */this.documentElement = null;
				/* ==== /Public ==== */
				
				++num; // Track number of current instances
			};
		});
		
		var Deriv = new Class( function () {
			/* ==== Static (Private) ==== */
			var num = 0;
			var isGood = "of course!";
			/* ==== /Static (Private) ==== */
			
			// Static (Public)
			this.Static({
				Count: function () {
					return num;
				}
			// Private members
			}).Private({
				AreWeGoodOrBad: function (g) { return function () {
					return isGood;
				}}
			// Protected members
			}).Protected({
				DontTellMum: function (g) { return function () {
					return true;
				}}
			// Public members
			}).Public({
				Say: function (_) { return function ( msg ) {
					alert("From Deriv: " + msg);
				}}
			// Misc.
			}).Export("Deriv");
			
			// __construct
			return function ( _ ) {
				++num; // Track number of current instances
			};
		}, {
			extend: Document
			, implement: IDocument
		});
		
		var Deriv2 = new Class( function () {
			/* ==== Static (Private) ==== */
			var num = 0;
			var isGood = "of course!";
			/* ==== /Static (Private) ==== */
			
			// Static (Public)
			this.Static({
				Count: function () {
					return num;
				}
			// Private members
			}).Private({
				/*AreWeGoodOrBad: function (g) { return function () {
					return isGood;
				}}*/
			// Public members
			}).Public({
				Say: function (_) { return function ( msg ) {
					alert("From Deriv2: " + msg);
				}}
			// Misc.
			}).Export("Deriv2");
			
			// __construct
			return function ( _ ) {
				++num; // Track number of current instances
			};
		}, {
			extend: Deriv
		});
		
		var deriv2 = new Deriv2();
		deriv2.Say("hey hey hey!");
		alert(deriv2.test() + "," + deriv2.test());
		//alert(deriv2.test());
		
		var deriv = new Deriv();
		alert(Deriv.Count());
		alert(deriv.AreWeGoodOrBad);
		deriv.Say("ahar me hartys");
		alert(deriv.createElement("div"));
		alert(deriv.test() + "," + deriv.test() + "," + deriv.test());
		
		var doc = new Document( "doct", "imp" );
		var doc2 = new Document( "doct", "imp" );
		alert(Document.Count());
		alert(doc.test() + "," + doc.test() + "," + doc.test());
		
		alert(doc.WeAreFamily + "," + deriv.WeAreFamily + "," + deriv2.WeAreFamily);
		alert(doc.AreWeFamily() + "," + deriv.AreWeFamily() + "," + deriv2.AreWeFamily());
		alert(doc.GetSecrets() + "," + deriv.GetSecrets() + "," + deriv2.GetSecrets());
		
		//alert(doc.Say+","+ deriv.Say+","+ deriv2.Say);
		
		
		
		window.Element = function Element() {	// Expose global & give name
			
		};
		Element.prototype.constructor = Node;
		// DOM HTMLElement ( interface )
		window.HTMLElement = function HTMLElement() {	// Expose global & give name
			// Interface conformance checks
			Assert( this.id !== undefined, arguments.callee, "property HTMLElement::id must be set" );
			Assert( this.title !== undefined, arguments.callee, "property HTMLElement::title must be set" );
			Assert( this.lang !== undefined, arguments.callee, "property HTMLElement::lang must be set" );
			Assert( this.dir !== undefined, arguments.callee, "property HTMLElement::dir must be set" );
			Assert( this.className !== undefined, arguments.callee, "property HTMLElement::className must be set" );
			
			Element.call(this);	// Super
		};
		HTMLElement.prototype.constructor = Element;
		// DOM HTMLHtmlElement class
		window.HTMLHtmlElement = function HTMLHtmlElement() {	// Expose global & give name
			// Interface conformance checks
			//Assert( this.version !== undefined, arguments.callee, "property HTMLHtmlElement::version must be set" );
			
			HTMLElement.call(this);	// Super
		};
		HTMLHtmlElement.prototype.constructor = HTMLElement;
		// DOM HTMLHeadElement class
		window.HTMLHeadElement = function HTMLHeadElement() {	// Expose global & give name
			// Interface conformance checks
			//Assert( this.profile !== undefined, arguments.callee, "property HTMLHeadElement::profile must be set" );
			
			HTMLElement.call(this);	// Super
		};
		HTMLHeadElement.prototype.constructor = HTMLElement;
	}
	
	
	
	// Handle adding an event listener to an element
	//	TODO: add DOM lev0)
	function AddEventListener( el, nameEvent, funcHandler ) {
		arr_hshEventHandlers.push( { el: el, nameEvent: nameEvent, funcHandler: funcHandler } );
		// W3C
		if ( window.addEventListener ) {
			if ( nameEvent === "mousewheel" ) {
				el.addEventListener("DOMMouseScroll", funcHandler, false);
			} else {
				el.addEventListener(nameEvent, funcHandler, false);
			}
		// IE
		} else if ( window.attachEvent ) {
			el.attachEvent("on" + nameEvent, funcHandler);
		}
	}
	
	// Cleanup operations when document is finished with
	AddEventListener(window, "unload", function () {
		/* ==== Malloc ==== */
		var idx = arr_hshEventHandlers.length - 1;
		var hshEventHandler;
		/* ==== /Malloc ==== */
		
		// Detach event handlers
		if ( idx > -1 ) {
			// W3C
			if ( window.removeEventListener ) {
				do {
					hshEventHandler = arr_hshEventHandlers[ idx ];
					if ( hshEventHandler.nameEvent === "mousewheel" ) {
						hshEventHandler.el.removeEventListener("DOMMouseScroll", hshEventHandler.funcHandler, false);
					} else {
						hshEventHandler.el.removeEventListener(hshEventHandler.nameEvent, hshEventHandler.funcHandler, false);
					}
				// Post-dec used as zero'th wanted
				} while ( idx-- );
			// IE
			} else if ( window.detachEvent ) {
				do {
					hshEventHandler = arr_hshEventHandlers[ idx ];
					hshEventHandler.el.detachEvent("on" + hshEventHandler.nameEvent, hshEventHandler.funcHandler);
				// Post-dec used as zero'th wanted
				} while ( idx-- );
			}
		}
	});
	
	function ProcessCSS( css ) {
		var rule, selector, list_parts;
		
		// From Sizzle
		var regexID = /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/;
		var regexClass_Single = /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/;
		var regexClass_Multi = /(?:\.((?:[\w\u00c0-\uFFFF-]|\\.)+))+/;
		var regexName = /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/;
		var regexAttr = /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/;
		var regexTag = /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/;
		var regexChild = /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/;
		var regexPos = /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/;
		//var regexPseudo = /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/;
		var regexPseudoClass = /:\s*(link|visited|active|hover|focus|(?:first|last|nth|nth-last|only)-child|lang|(?:first|last|nth|nth-last|only)-of-type|root|empty|target|enabled|disabled|checked|not)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/;
		var regexPseudoClass_Neg = /:\s*not\s*(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\1\))/g;
		// In CSS3, pseudo-elements have a double-colon (support single-colon for CSS1/2)
		var regexPseudoElement = /::?\s*(first-letter|first-line|before|after|selection)/;
		
		var regex_styleAll = /\s*([^:]+)\s*:\s*([^;]+)\s*;/g, regex_style = /\s*([^:]+)\s*:\s*([^;]+)\s*;/;
		var regex_ruleAll = /\s*((?:"[^"]*"|[^"{])*)\s*\{\s*([^}]*)\s*\}/g, regex_rule = /\s*((?:"[^"]*"|[^"{}])*)\s*\{\s*([^}]*)\s*\}/;
		// Only selectors supported by IE6 should match this
		//	( NB: negative lookahead used to ensure IE6 is not passed multiple pseudo-classes
		//	as it does not support them: ie. ":link:visited or :visited:link" match even though mutually exclusive )
		var regex_selectorOK = /^(,?\s*(\*|[\w-_]+|#\s*[\w-_]+|\.\s*[\w-_]+(?![^\s]*\.\s*[\w-_]+)|:\s*(?:link|visited)(?![^\s]*:\s*(?:link|visited)))\s*)+$/;
		
		// Lookup map for specificity prefixes to use
		//	to match original selector
		var map_specificity_selector = {
			000: ""
			, 001: "html"
			, 002: "html body"
			
			, 010: "." + classPrefix_Root
			, 011: "html." + classPrefix_Root
			, 012: "html." + classPrefix_Root + " body"
			
			, 021: "html." + classPrefix_Root + " ." + classPrefix_Body
			, 022: "html." + classPrefix_Root + " body." + classPrefix_Body
		};
		// <= IE6 do not support multiple class selectors (ie. ".class1.class2"
		//	so each group of them only counts once towards the specificity
		var regexClass = isIE && version <= 6 ? regexClass_Multi : regexClass_Single;
		
		var name, value;
		
		var cssNew = "";
		
		var idx, list, len;
		var idx_style, list_style, len_list_style;
		var specificity;
		var classSimple;
		
		// Strip comments
		css = css.replace(/\/\*[\s\S]*?\*\//g, "");
		
		if ( list = css.match(regex_ruleAll) ) {
			for ( idx = 0, len = list.length ; idx < len ; ++idx ) {
				list_parts = regex_rule.exec(list[ idx ]);
				selector = list_parts[ 1 ].Trim();	// Pull selector
				list_style = list_parts[ 2 ].match(regex_styleAll);	// Must parse styles list
				
				// Unsupported selector: must intervene & use jQuery selector engine
				if ( !regex_selectorOK.test(selector) ) {
					// Store original, unsupported selector & rule index ( see below for rule object )
					list_data_ruleFixed.push({ selector: selector });
					
					specificity = 0;
					
					/* ====== */
					/* Generate unique, special class selector so may be quickly applied when needed
					 *	... remember that specificity matters, so we must calculate specificity
					 *	of original selector and match with replacement one
					 * NB: univeral selector does not affect specificity
					 */
					// Empty literal strings, these have no impact on specificity
					//	but may contain strings which could be matched as selectors below
					selector = selector.replace(/"[^"]*"/g, '""');
					// "Selectors inside the negation pseudo-class are counted like any other,
					//	but the negation itself does not count as a pseudo-class. "
					//	(remove all :not(...) and replace with just the content inside the parens)
					selector = selector.replace(regexPseudoClass_Neg, "$2");
					
					while ( regexID.test(selector) ) { specificity += 100; selector = selector.replace(regexID, ""); }
					while ( regexClass.test(selector) ) { specificity += 10; selector = selector.replace(regexClass, ""); }
					while ( regexAttr.test(selector) ) { specificity += 10; selector = selector.replace(regexAttr, ""); }
					// NB: negation pseudo-class will already have been removed (see above)
					while ( regexPseudoClass.test(selector) ) { specificity += 10; selector = selector.replace(regexPseudoClass, ""); }
					while ( regexPseudoElement.test(selector) ) { specificity += 1; selector = selector.replace(regexPseudoElement, ""); }
					// Do this last as its simple grammar would match the above selectors
					while ( regexTag.test(selector) ) { specificity += 1; selector = selector.replace(regexTag, ""); }
					
					// Generate simple class selector for targeting
					classSimple = "." + classPrefix + (list_data_ruleFixed.length - 1);
					
					// The Now!W3C replacement simple class itself has specificity of 010
					specificity -= 10;
					
					// Generate simple selector with correct specificity
					if ( specificity > 0 ) {
						// Unreachable specificity bounds - round down
						if ( specificity > 002 && specificity < 010 ) { specificity = 002; }
						else if ( specificity > 012 && specificity < 021 ) { specificity = 012; }
						else if ( specificity > 022 ) { specificity = 022; }
						
						// Also allow selector to be applied alone in case specificity
						//	cannot be attained (eg. for "html::root { ... }"
						selector = classSimple + ", " + map_specificity_selector[ specificity ] + " " + classSimple;
					} else {
						selector = classSimple;
					}
					/* === / === */
				}
				
				cssNew += selector + " {\n";
				
				if ( list_style ) {
					for ( idx_style = 0, len_list_style = list_style.length ; idx_style < len_list_style ; ++idx_style ) {
						list_parts = regex_style.exec(list_style[ idx_style ]);
						name = list_parts[ 1 ]; value = list_parts[ 2 ];
						cssNew += "\t" + name + ": " + value + ";\n";
					}
				}
				cssNew += "}\n";
			}//alert(cssNew);
		}
		return cssNew;
	}
	function EnumStyleSheets() {
		var elStyleSheet, stylesheet, css;
		var idx, list, len;
		
		//document.body.innerText = document.getElementsByTagName("head")[0].innerHTML;
		
		// Process linked-in stylesheets: must download original source
		//	as not available by eg. .innerHTML
		for ( idx = 0, list = document.getElementsByTagName("link"), len = list.length ; idx < len ; ++idx ) {
			if ( list[ idx ].rel.toLowerCase() == "stylesheet" /*&& list[idx].href=="styles/formcontrols.css"*/ ) {
				stylesheet = list[ idx ];
				$.ajax({
					type: "GET"
					, context: stylesheet
					, url: stylesheet.href
					, success: function ( css ) {
						this.styleSheet.cssText = ProcessCSS(css);
					}
				});
			}
		}
		// Process inline style elements
		for ( idx = 0, list = document.getElementsByTagName("style"), len = list.length ; idx < len ; ++idx ) {
			stylesheet = list[ idx ];
			
			// Must not read styleSheet until innerHTML read
			//	( otherwise innerText will be parsed & damaged by browser )
			css = ProcessCSS(stylesheet.innerHTML);
			stylesheet.styleSheet.cssText = css;//alert(css);
		}
		//alert(list_data_ruleFixed[6].selector);
	}
	
	function CreateTempElement( nodeName ) {
		var el = document.createElement(nodeName || "object");
		el.style.position = "absolute";
		el.style.left = "-1000px"; el.style.top = 0;
		el.style.clip = "rect(0 0 0 0)";
		el.style.fontSize = el.style.lineHeight = 0;	// IE6 allow tiny element
		return el;
	}
	
	function AddRecalc( name, regex_val, fnReplace ) {
		name = NowW3C.ToJSStyle(name);
		listRecalc.push({ name: name, regex_val: regex_val, fnReplace: fnReplace });
	}
	
	function FixEventModel() {
		self.addEventListener = AddEventListener;
	}
	function FixStyling() {
		// <html> and <body> elements always exist,
		//	apply classes to these for use in specificity matching
		$(document.documentElement).addClass(classPrefix_Root);
		$(document.body).addClass(classPrefix_Body);
		
		EnumStyleSheets();
		
		/* ==== Expression-based fixes ==== */
		// NB: IE6 does not support hyphen-prefixed properties
		//	( do not attempt to use for vendor prefixes etc. )
		var stylesheet = document.createStyleSheet();
		// For fixing the IE6 bug where :link:visited matches
		//	( even though the two are mutually exclusive )
		stylesheet.addRule(":link", "NowW3C-Link: link");
		stylesheet.addRule(":visited", "NowW3C-Link: visited");
		//stylesheet.addRule("*", "width:expression(NowW3C.CalcWidth(this));");
		/* ==== /Expression-based fixes ==== */
		
		// "Doubled margin" / "Peekaboo" bugs
		// http://www.positioniseverything.net/explorer/doubled-margin.html
		// http://www.positioniseverything.net/explorer/peekaboo.html
		// See also http://www.positioniseverything.net/explorer/floatIndent.html
		AddRecalc("float", /^left|right$/, function ( list_match, el, val ) {
			//IE.Layout.GiveLayout(el.parentNode);
			el.style.display = "inline";
		});
		
		AddRecalc("min-width", /^/, function ( list_match, el, val ) {
			//el.style.setExpression("width", jsCalcWidth);
		});
		AddRecalc("max-width", /^/, function ( list_match, el, val ) {
			//el.style.setExpression("width", jsCalcWidth);
		});
		AddRecalc("min-height", /^/, function ( list_match, el, val ) {
			
		});
		AddRecalc("max-height", /^/, function ( list_match, el, val ) {
			
		});
	}
	
	// Advanced jQuery selector filter extensions
	//	( see description under Setup() for details )
	var HookSelectorFilter;
	(function () {
		var Expr = $.expr, Sizzle = jQuery.find;
		// Would be nice if this wasn't private to jQuery...
		var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g;
		
		// List of filters added (requires modification of Expr.preFilter.PSEUDO below,
		//	this is jQuery internal but extensions system is insufficient)
		var list_regexCustomFilter = { POS: Expr.match.POS, CHILD: Expr.match.CHILD };
		
		HookSelectorFilter = function ( type, regex, fnPreFilter, fnFilter ) {
			var fnPreFilter_Old, fnFilter_Old;
			
			// Install filter regex & its custom filtering function
			list_regexCustomFilter[ type ] = regex;
			Expr.match[ type ] = regex;
			RebuildMatcher(type);
			
			// Allow hook to call previous hook in chain by return undefined
			if ( Expr.preFilter[ type ] ) {
				fnPreFilter_Old = Expr.preFilter[ type ];
				Expr.preFilter[ type ] = function ( list_match ) {
					var result = fnPreFilter(list_match);
					return result !== undefined ? result : fnPreFilter_Old(list_match);
				};
			// Where no previous hook, link directly for speed
			} else {
				Expr.preFilter[ type ] = fnPreFilter;
			}
			
			// Allow hook to call previous hook in chain by return undefined
			if ( Expr.filter[ type ] ) {
				fnFilter_Old = Expr.filter[ type ];
				Expr.filter[ type ] = function ( el, list_match ) {
					var result = fnFilter(el, list_match);
					return result !== undefined ? result : fnFilter_Old(el, list_match);
				};
			// Where no previous hook, link directly for speed
			} else {
				Expr.filter[ type ] = fnFilter;
			}
		};
		
		// Adapted from jQuery setup
		function RebuildMatcher( type ) {
			Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
			Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
				return "\\" + (num - 0 + 1);
			}));
		}
		
		// Adapted from jQuery setup
		//	WARNING: This is not optimal - jQuery internals could change at any time
		Expr.preFilter.PSEUDO = function ( match, curLoop, inplace, result, not ) {
			if ( match[1] === "not" ) {
				// If we're dealing with a complex expression, or a simple one
				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
					match[3] = Sizzle(match[3], null, null, curLoop);
				} else {
					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
					if ( !inplace ) {
						result.push.apply( result, ret );
					}
					return false;
				}
			// New: custom filters
			} else {
				for ( var type in list_regexCustomFilter ) {
					if ( list_regexCustomFilter[ type ].test(match[ 0 ]) ) { return true; }
				}
			}
			
			return match;
		};
	})();
	
	// Takes "an+b" format equation
	function NEquation( idx, val ) {
		val = val.toString();
		
		/* ==== Parse eqn ==== */
		val1 = parseFloat(val);
		if ( isNaN(val1) ) val1 = 1;
		// +1 to skip the "n"
		val2 = parseFloat(val.substr(val1.toString().length + 1));	
		if ( isNaN(val2) ) val2 = 0;
		if ( val.indexOf("n") === -1 ) { val2 = val1; val1 = 0; }
		/* ==== /Parse eqn ==== */
		
		// To one-based
		++idx;
		// Subtract "b" offset
		idx -= val2;
		// Cleanly divisible by coeff of "n"?
		return (val1 === 0) ? (idx === 0) : (idx % val1 === 0);
	}
	
	function Setup() {
		var Expr = $.expr;
		
		/* ===== Augment jQuery ===== */
		/*
		 *	By default, jQuery does not support the full range of CSS3 selectors,
		 *	because it is JavaScript-centric and many of them have little use
		 *	outside CSS. However, to emulate CSS support for older browsers,
		 *	we need to add support for all selectors here.
		 *	( NB: originally used jQuery extensions under $.extend($.expr[":"], { ... });
		 *		but this is unsuitable for descendant selectors:
		 *		eg. "ul:first-of-type li:first-of-type" will not work properly,
		 *		when processing the UL part the element passed will be HTML (documentElement)
		 *		and the element array will only have the HTML element inside too. )
		 */
		HookSelectorFilter("OF_TYPE", /:(only|nth|last|first|nth-last)-of-type(?:\((even|odd|[\dn+\-]*)\))?/
		// Pre-filter
		, undefined
		// Filter
		, function ( el, list_match ) {
			var type = list_match[ 1 ];
			var list_elSibling = $(el.parentNode).children(), idx, val, val1, val2;
			var selector_type = el.nodeName != "INPUT" ? el.nodeName : el.nodeName + "[type=" + el.type + "]";
			
			switch ( type ) {
			case "only":
				return list_elSibling.filter(selector_type).length === 1;
			case "first":
				return el === list_elSibling.filter(selector_type + ":first")[ 0 ];
			case "nth":
				list_elSibling = list_elSibling.filter(selector_type);
				idx = $.inArray(el, list_elSibling);
				return NEquation(idx, list_match[ 2 ]);
			case "nth-last":
				list_elSibling = list_elSibling.filter(selector_type);
				idx = list_elSibling.length - $.inArray(el, list_elSibling) - 1;
				return NEquation(idx, list_match[ 2 ]);
			case "last":
				return el === list_elSibling.filter(selector_type + ":last")[ 0 ];
			}
		});
		HookSelectorFilter("CHILD", /:(only|nth|last|first|nth-last)-child(?:\((even|odd|[\dn+-]*)\))?/
		// Pre-filter
		, function ( list_match ) {
			if ( list_match[ 1 ] === "nth-last" ) {
				list_match.typeHooked = list_match[ 1 ]; list_match[ 1 ] = "nth";
				// Bypass jQuery's built-in pre-filter,
				//	as we use NEquation to parse the nth*(an+b) equations
				return list_match;
			}
			return undefined;
		// Filter
		}, function ( el, list_match ) {
			var type = list_match[ 1 ];
			var list_elSibling = $(el.parentNode).children(), idx, val, val1, val2;
			
			if ( list_match.typeHooked === "nth-last" ) {
				// No addl. filtering to do: just looking at children of parentNode
				idx = list_elSibling.length - $.inArray(el, list_elSibling) - 1;
				return NEquation(idx, list_match[ 2 ]);
			} else { // Pass to old handler
				return undefined;
			}
		});
		HookSelectorFilter("OTHER", /:(root|link|visited|hover|active|focus|target|lang|indeterminate)(?:\(([^)]*)\))?/
		// Pre-filter
		, undefined
		// Filter
		, function ( el, list_match ) {
			switch ( list_match[ 1 ] ) {
			case "root": // For HTML4, this is just the <html> element
				return el === document.documentElement;
			// :link and :visited are supported in IE6 but multiple
			//	pseudo-classes are not, jQuery must then support them
			//	( NB: these custom properties are set in FixStyling() )
			case "link":
				return el.currentStyle[ "NowW3C-Link" ] === "link";
			case "visited":
				return el.currentStyle[ "NowW3C-Link" ] === "visited";
			case "hover":
				return false;
			case "active":
				return false;
			case "focus":
				return el === document.activeElement; // IE only
			case "indeterminate": // The 3rd state of a checkbox
				return el.indeterminate;
			}
		});
		/* ===== /Augment jQuery ===== */
		
		//Expr.match.CHILD = ;
		
		//var fnPreFilterCHILD_Old = Expr.preFilter.CHILD;
		//Expr.preFilter.CHILD = ;
		
		//var fnFilterCHILD_Old = Expr.filter.CHILD;
		//Expr.filter.CHILD = ;
		
		/*
		// Install jQuery extensions to support all CSS3 selectors
		$.extend($.expr[":"], {
			"only-of-type" : function ( el, idx, list_match, list_el ) {
				return $(list_el).filter(el.nodeName != 'INPUT' ? el.nodeName : el.nodeName + '[type=' + el.type + ']').length === 1;
			}, "first-of-type" : function ( el, idx, list_match, list_el ) {
				var s = "";
				var i = 0;
				for ( var i = 0 ; i< list_el.length ; ++i ) {
					s += list_el[i].nodeName + ",";
				}
				top.status = s + ":" + idx + ":" + el.nodeName + "," + list_match;
				
				return el === $(list_el).filter(el.nodeName != 'INPUT' ? el.nodeName : el.nodeName + '[type=' + el.type + ']')[ 0 ];
			}, "nth-of-type" : function ( el, idx, list_match, list_el ) {
				//alert(list_match);
				// Remember that CSS indexes are 1-based, so must -1
				return el === $(list_el).filter(el.nodeName != 'INPUT' ? el.nodeName : el.nodeName + '[type=' + el.type + ']')[ list_match[ 3 ] - 1 ];
			}, "last-of-type" : function ( el, idx, list_match, list_el ) {
				return el === $(list_el).filter((el.nodeName != 'INPUT' ? el.nodeName : el.nodeName + '[type=' + el.type + ']') + ":last")[ 0 ];
				
			}, "nth-last-child" : function ( el, idx, list_match, list_el ) {
				// Remember that CSS indexes are 1-based
				var list_elSibling = $.sibling(el);
				return el === list_elSibling[ list_elSibling.length - list_match[ 3 ] ];
				//return $.sibling(el, $.sibling(el).length - 1 - list_match[ 3 ]).cur;
			}
		});*/
	}
	self.attachEvent("onload", function () {
		elTemp = CreateTempElement();
		
		Setup();
		FixEventModel();
		FixStyling();
		
		// TEMP!
		self.setInterval(NowW3C.Update, 1000);
		NowW3C.Update();
	});
	
	function GetElementsByTagName() {
		
	}
	
	function Assert( condition ) {
		if ( !condition ) {
			throw "Assertion failed";
		}
	}
	
	/* ========= Augmentations ========= */
	// Strip leading & trailing whitespace
	String.prototype.Trim = function () {
		return this.replace(/^\s+|\s+$/g, "");
	};
	// Repeat a string the specified no. of times
	String.prototype.Repeat = function ( num ) {
		return (new Array( num )).join(this);
	};
	Function.prototype.GetName = function () {
		if ( this.name ) {
			return this.name;
		// ( NB: regex adapted from http://phpjs.org/functions/print_r:493 )
		} else if ( list_match = /\W*function\s+([\w\$]+)\s*\(/.exec(this) ) {
			return list_match[ 1 ];
		} else {
			return "(Anonymous)";
		}
	};
	/* ========= /Augmentations ========= */
	
	/* ==== Exports ==== */
	window.NowW3C = NowW3C;
	/* ==== /Exports ==== */
})(self);